//
//  YDNetworkTool.swift
//  YD_DataModel
//
//  Created by 钟志远 on 2021/11/29.
//  Copyright © 2021 alyadan. All rights reserved.
//

import Foundation
import SwiftyJSON
import RxSwift
import Moya

public protocol ResponseHandler {
    func dealResponse<T: TargetType>(response: Response, target: T) throws -> Observable<JSON>
    func dealAuthError<T: TargetType>(response: Response, target: T) throws -> Observable<JSON>
}


public protocol MoyaProviderFactoryType {
    func makeProvider<T: TargetType>(target: T) -> MoyaProvider<T>
}

public extension Error {
    var yd_msg: String? {
        guard let ydError = self as? YDNetworkTool.HttpError else {
            return self.localizedDescription
        }
        return ydError.msg
    }
}

public class YDNetworkTool {
    
    public enum HttpError: Error {
        case connectError(Error)
        case serverError(URLRequest?, Int, String, JSON)
        
        var msg: String? {
            switch self {
            case HttpError.serverError(_, _, let msg, _):
                return msg
            case HttpError.connectError(let error):
                return error.localizedDescription
            }
        }
    }
    
    static public var responseDeal: ResponseHandler = ResponseHandlerExample()
    static public var providerFactory: MoyaProviderFactoryType = DefaultMoyaProviderFactory()
    
    
    static public func requestRx<T: TargetType>(target: T, makeProvider: ((T) -> MoyaProvider<T>)? = nil) -> Observable<JSON> {
        
        return Observable<JSON>.create { (observer: AnyObserver<JSON>) in
            
            let requestProvider = makeProvider != nil ? makeProvider!(target): providerFactory.makeProvider(target: target)
//            let requestProvider = MoyaProvider<T>(requestClosure: requestTimeoutClosure(target: target))
            let cancelable = requestProvider.request(target) { result in
                
                switch result {
                case .success(let response):
                    do {
                        _ = try responseDeal.dealResponse(response: response, target: target)
                            .subscribe(onNext: observer.onNext, onError: observer.onError, onCompleted: observer.onCompleted)
                        
                    } catch(let error) {
                        observer.onError(error)
                    }
                    break
                case .failure(let error):
                    observer.onError(error)
                }
            }
            
            let disposable = Disposables.create {
                cancelable.cancel()
            }
            return disposable
            
        }
    }
}
